package gui;

import java.awt.Dialog.ModalExclusionType;
import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;

import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker.StateValue;
import javax.swing.UIManager;

import org.netbeans.api.visual.widget.Widget;
import org.openide.util.Exceptions;

import parser.Block;
import parser.FloorPlan;
import parser.FloorPlanParser;
import parser.ParseResult;
import parser.SAexecuting;
import simuAnnealing.SAconfigurations;
import simuAnnealing.SimulatedAnnealing;
import simuAnnealing.Solution;
import simuAnnealing.Solution.alogrithmToUse;

import javax.swing.ImageIcon;
import java.awt.Color;
import java.awt.Frame;
import java.awt.GridBagConstraints;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.awt.SystemColor;
import java.awt.Font;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import javax.swing.JLabel;
import javax.swing.JButton;

/**
 * 
 * @author Fozy
 *
 */

public class PowerAwareFP extends javax.swing.JFrame {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	
	private static final String SA_NOT_EXECUTED = "                                         " +
			"         Simulated Annealing has not been yet Executed    ";
	private FloorPlan initialFloorPlan;
	private Solution solution;
	private JFrame myFrame;
	private GraphicalBlockRepresentation graphBlocks;
	private GraphicalBlockRepresentation initialFP;
	
	public PowerAwareFP() throws IOException {
		initComponents();
	}

	/**
	 * This method is called from within the constructor to initialize the form.
	 * WARNING: Do NOT modify this code. The content of this method is always
	 * regenerated by the Form Editor.
	 */
	@SuppressWarnings("unchecked")
	private void initComponents() {
		
		myFrame = this;
		this.setUndecorated(true);
	
		java.awt.GridBagConstraints gridBagConstraints;

		contentBar = new javax.swing.JToolBar();
		contentBar.setBackground(new Color(0, 0, 0));
		btnParseFile = new javax.swing.JButton();
		btnParseFile.setBackground(Color.BLACK);
		btnExecute = new javax.swing.JButton();
		btnExecute.setBackground(new Color(0, 0, 0));
		btnCostGraph = new javax.swing.JButton();
		btnCostGraph.setBackground(new Color(0, 0, 0));
		mainPageDisplay = new javax.swing.JScrollPane();
		displayPanel = new javax.swing.JPanel();
		displayPanel.setBackground(new Color(255, 250, 240));
		stateBar = new javax.swing.JToolBar();
		stateBar.setBackground(new Color(255, 250, 240));
		stateLabel = new javax.swing.JLabel();
		progressBar = new javax.swing.JProgressBar();
		progressBar.setForeground(new Color(128, 0, 0));
		progressBar.setBackground(new Color(255, 250, 240));
		menuBar = new javax.swing.JMenuBar();
		menuBar.setBackground(new Color(0, 0, 0));
		menuFile = new javax.swing.JMenu();
		menuFile.setForeground(new Color(255, 255, 255));
		menuFile.setFont(new Font("Tahoma", Font.PLAIN, 14));
		menuFile.setBackground(new Color(0, 0, 0));
		menuInsertInputFile = new javax.swing.JMenuItem();
		menuInsertInputFile.setFont(new Font("Tahoma", Font.PLAIN, 14));
		menuInsertInputFile.setForeground(new Color(0, 0, 0));
		menuInsertInputFile.setBackground(new Color(255, 250, 240));
		menuExit = new javax.swing.JMenuItem();
		menuExit.setFont(new Font("Tahoma", Font.PLAIN, 14));
		menuExit.setForeground(new Color(0, 0, 0));
		menuExit.setBackground(new Color(255, 250, 240));
		menuEdit = new javax.swing.JMenu();
		menuEdit.setFont(new Font("Tahoma", Font.PLAIN, 14));
		menuEdit.setForeground(new Color(255, 255, 255));
		menuEdit.setBackground(new Color(0, 0, 0));
		menuConfig = new javax.swing.JMenuItem();
		menuConfig.setFont(new Font("Tahoma", Font.PLAIN, 14));
		menuConfig.setForeground(new Color(0, 0, 0));
		menuConfig.setBackground(new Color(255, 250, 240));

		setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
		setTitle("Power-Aware FloorPlanning");
		getContentPane().setLayout(new java.awt.GridBagLayout());

		contentBar.setFloatable(false);
		contentBar.setRollover(true);

		btnParseFile.setIcon(new ImageIcon(PowerAwareFP.class
				.getResource("/Images/open.png")));
		btnParseFile.setToolTipText("Open parsable file..");
		btnParseFile.setFocusable(false);
		btnParseFile
				.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
		btnParseFile.setMargin(new java.awt.Insets(10, 10, 10, 10));
		btnParseFile.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
		btnParseFile.addActionListener(new java.awt.event.ActionListener() {
			public void actionPerformed(java.awt.event.ActionEvent evt) {
				parseInputFile(evt);
			}
		});
		contentBar.add(btnParseFile);

		btnExecute.setIcon(new ImageIcon(PowerAwareFP.class
				.getResource("/Images/execute.png")));
		btnExecute.setToolTipText("Execute Simulated Annealing");
		btnExecute.setFocusable(false);
		btnExecute.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
		btnExecute.setMargin(new java.awt.Insets(10, 10, 10, 10));
		btnExecute.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
		btnExecute.addActionListener(new java.awt.event.ActionListener() {
			public void actionPerformed(java.awt.event.ActionEvent evt) {
				executeWasPerformed(evt);
			}
		});
		contentBar.add(btnExecute);

		btnCostGraph.setIcon(new ImageIcon(PowerAwareFP.class
				.getResource("/Images/graph.png"))); 
		btnCostGraph.setToolTipText("Cost function Graph");
		btnCostGraph.setFocusable(false);
		btnCostGraph
				.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
		btnCostGraph.setMargin(new java.awt.Insets(10, 10, 10, 10));
		btnCostGraph.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
		btnCostGraph.addActionListener(new java.awt.event.ActionListener() {
			public void actionPerformed(java.awt.event.ActionEvent evt) {
				btnCostGraphPerformed(evt);
			}
		});
		contentBar.add(btnCostGraph);

		gbc_contentBar = new java.awt.GridBagConstraints();
		gbc_contentBar.gridwidth = java.awt.GridBagConstraints.REMAINDER;
		gbc_contentBar.fill = java.awt.GridBagConstraints.BOTH;
		gbc_contentBar.weightx = 1.0;
		getContentPane().add(contentBar, gbc_contentBar);
		
		btnShowInitialFP = new JButton();
		btnShowInitialFP.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				
				if (solution == null) {
					JOptionPane
							.showMessageDialog(myFrame,
									"You must have an initial FP first, Go to File -> Choose Initial FP");
				}
				
				else{
					JDialog dialog = new JDialog();
					dialog.setBounds(displayPanel.getBounds());
					initialFP = new GraphicalBlockRepresentation();
					
					TreeNodesSchema schema = new TreeNodesSchema(initialFloorPlan);
					
					Widget node;
					
					for(Block block : schema.getBlocks()){
						initialFP.setImageWidth((int)block.getHorizontalLength()*20);
						initialFP.setImageHeight((int)block.getVerticalLength()*20);
						node = initialFP.addNode(block);
	
						node.setPreferredLocation(schema.placeBlock(block,dialog.getBounds()));
					
					}
					
			        dialog.setContentPane(initialFP.createView());
			        dialog.setModal(true);
			        dialog.pack();
			        dialog.setLocationRelativeTo(myFrame);
			        dialog.setVisible(true);
				}
			}
		});
		btnShowInitialFP.setBackground(new Color(0, 0, 0));
		btnShowInitialFP.setIcon(new ImageIcon(PowerAwareFP.class
				.getResource("/Images/repeat.png"))); 
		btnShowInitialFP.setToolTipText("Show initial FloorPlan");
		btnShowInitialFP.setFocusable(false);
		btnShowInitialFP
				.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
		btnShowInitialFP.setMargin(new java.awt.Insets(10, 10, 10, 10));
		btnShowInitialFP.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
		contentBar.add(btnShowInitialFP);
		
		lblStatus = new JLabel(SA_NOT_EXECUTED);
		lblStatus.setForeground(new Color(255, 250, 250));
		lblStatus.setFont(new Font("Tahoma", Font.PLAIN, 16));
		contentBar.add(lblStatus);

		displayPanel.setLayout(new java.awt.BorderLayout());
		mainPageDisplay.setViewportView(displayPanel);

		gridBagConstraints = new java.awt.GridBagConstraints();
		gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
		gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
		gridBagConstraints.weightx = 1.0;
		gridBagConstraints.weighty = 1.0;
		getContentPane().add(mainPageDisplay, gridBagConstraints);

		stateBar.setRollover(true);
		stateBar.add(stateLabel);

		progressBar.setStringPainted(true);
		stateBar.add(progressBar);

		gbc_stateBar = new java.awt.GridBagConstraints();
		gbc_stateBar.gridwidth = java.awt.GridBagConstraints.REMAINDER;
		gbc_stateBar.fill = java.awt.GridBagConstraints.HORIZONTAL;
		gbc_stateBar.weightx = 1.0;
		getContentPane().add(stateBar, gbc_stateBar);

		menuFile.setText("File");

		menuInsertInputFile.setAccelerator(javax.swing.KeyStroke.getKeyStroke(
				java.awt.event.KeyEvent.VK_O,
				java.awt.event.InputEvent.CTRL_MASK));

		menuInsertInputFile.setText("Choose initial FP");
		menuInsertInputFile
				.addActionListener(new java.awt.event.ActionListener() {
					public void actionPerformed(java.awt.event.ActionEvent evt) {
						parseFP(evt);
					}
				});
		menuFile.add(menuInsertInputFile);

		menuExit.setAccelerator(javax.swing.KeyStroke.getKeyStroke(
				java.awt.event.KeyEvent.VK_F4,
				java.awt.event.InputEvent.ALT_MASK));
		menuExit.setText("Exit");
		menuExit.addActionListener(new java.awt.event.ActionListener() {
			public void actionPerformed(java.awt.event.ActionEvent evt) {
				exitActionPerformed(evt);
			}
		});
		
		mntmMinimize = new JMenuItem("Minimize");
		mntmMinimize.setFont(new Font("Tahoma", Font.PLAIN, 14));
		mntmMinimize.setForeground(new Color(0, 0, 0));
		mntmMinimize.setBackground(new Color(255, 250, 240));
		mntmMinimize.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				myFrame.setState(Frame.ICONIFIED);
			}
		});
		mntmMinimize.setAccelerator(javax.swing.KeyStroke.getKeyStroke(
				java.awt.event.KeyEvent.VK_M,
				java.awt.event.InputEvent.CTRL_MASK));
		menuFile.add(mntmMinimize);
		menuFile.add(menuExit);

		menuBar.add(menuFile);

		menuEdit.setText("Edit");

		menuConfig.setAccelerator(javax.swing.KeyStroke.getKeyStroke(
				java.awt.event.KeyEvent.VK_P,
				java.awt.event.InputEvent.CTRL_MASK));
		menuConfig.setText("Configurations");
		menuConfig.addActionListener(new java.awt.event.ActionListener() {
			public void actionPerformed(java.awt.event.ActionEvent evt) {
				configBtnPerformed(evt);
			}
		});
		menuEdit.add(menuConfig);

		menuBar.add(menuEdit);

		setJMenuBar(menuBar);

		pack();
	}

	private void drawBlocks(FloorPlan floorPlan) {
		
		TreeNodesSchema schema = new TreeNodesSchema(floorPlan);
		
		Widget node;
		
		graphBlocks = new GraphicalBlockRepresentation();
		
		for(Block block : schema.getBlocks()){
			graphBlocks.setImageWidth((int)block.getHorizontalLength()*20);
			graphBlocks.setImageHeight((int)block.getVerticalLength()*20);
			node = graphBlocks.addNode(block);

			node.setPreferredLocation(schema.placeBlock(block,displayPanel.getBounds()));
		
		}
		
		if(displayPanel.getComponentCount() != 0){
			displayPanel.remove(0);
		}
		
		displayPanel.add(graphBlocks.createView(),java.awt.BorderLayout.CENTER);
		displayPanel.revalidate();
		displayPanel.repaint();
		
	}

	private void exitActionPerformed(java.awt.event.ActionEvent evt) {
		this.dispose();
		System.exit(0);
	}

	private void performExecute(java.awt.event.ActionEvent evt) {
		if (solution == null) {
			JOptionPane
					.showMessageDialog(this,
							"You must have an initial FP first, Go to File -> Choose Initial FP");
		}
		
		else{
			progressBar.setValue(0);
			JDialog dialog = new JDialog(this);
			dialog.setTitle("Executing Simulated Annealing ..");
			dialog.getContentPane().add(progressBar);
			dialog.pack();
			dialog.setModal(true);
			dialog.setLocationRelativeTo(this);
			solution.setSimulatedAnnealingAlg(new SimulatedAnnealing());
			solution.executeSA();
			progressBarHandler().execute();
			dialog.setVisible(true);
		}
	}

	private void parseInputFile(java.awt.event.ActionEvent evt) {
		parseFP(evt);
	}

	private void executeWasPerformed(java.awt.event.ActionEvent evt) {
		performExecute(evt);
	}

	private void configBtnPerformed(java.awt.event.ActionEvent evt) {
		if (solution == null) {
			JOptionPane
					.showMessageDialog(this,
							"You must have an initial FP first, Go to File -> Choose Initial FP");
		} else {
			UserConfigurations configurationsPanel;
			JDialog dialog = new JDialog();
			configurationsPanel = new UserConfigurations(dialog, solution);
			dialog.setContentPane(configurationsPanel);
			dialog.setTitle("Configurations .. ");
			dialog.setModal(true);
			dialog.setUndecorated(true);
			dialog.setModalExclusionType(ModalExclusionType.APPLICATION_EXCLUDE);
			dialog.pack();
			dialog.setLocationRelativeTo(this);
			dialog.setVisible(true);
		}
	}

	private void parseFP(java.awt.event.ActionEvent evt) {
		JFileChooser browser = new JFileChooser();
		File selectedFile;

		browser.showOpenDialog(this);

		selectedFile = browser.getSelectedFile();

		if (selectedFile == null)
			return;

		try {

			FloorPlanParser parse = new FloorPlanParser(selectedFile);

			if (parse.getResult() != ParseResult.PARSE_SUCCESS) {
				JOptionPane
						.showMessageDialog(myFrame,
								"There was an error parsing the input file, please try again");
			}

			else {
				initialFloorPlan = parse.getFloorPlan();
				
				drawBlocks(initialFloorPlan);
				
				SAconfigurations config = new SAconfigurations();

				solution = new Solution(initialFloorPlan,
						alogrithmToUse.SIMULATED_ANNEALING, config);

				JOptionPane.showMessageDialog(myFrame,
						"Initial Floor-Plan (Solution) was built successfully");
			}

		} catch (IOException e) {
			JOptionPane
					.showMessageDialog(myFrame,
							"There was an error parsing the input file, please try again");
		} catch (NullPointerException e) {
			JOptionPane
					.showMessageDialog(myFrame,
							"There was an error parsing the input file, please try again");
		}

	}

	private void drawCostGraph(java.awt.event.ActionEvent evt) {
		if (solution == null
				|| (solution.getSimulatedAnnealingAlg()
						.getMidWayFinalSolution().size() == 0)) {
			JOptionPane
					.showMessageDialog(
							myFrame,
							"To be able to see the graph Simulated Annealing algorithm must be executed first");
		}

		else {
			SimulatedPlot saPlot;
			JDialog dialog = new JDialog();
			if(solution.getSimulatedConfigurations().getGraphMethod() == GraphPlotMode.BY_FINAL_SOLUTIONS){
				saPlot = new SimulatedPlot(solution,GraphPlotMode.BY_FINAL_SOLUTIONS);
			}
			else
			{
				saPlot = new SimulatedPlot(solution,GraphPlotMode.BY_ACTUAL_SOLUTIONS);
			}
	        dialog.setContentPane(saPlot);
	        dialog.setModal(true);
	        dialog.pack();
	        dialog.setLocationRelativeTo(myFrame);
	        dialog.setVisible(true);
		}
	}

	private void btnCostGraphPerformed(java.awt.event.ActionEvent evt) {
		drawCostGraph(evt);
	}

	private SAexecuting progressBarHandler() {
		SAexecuting handler = new SAexecuting();

		handler.addPropertyChangeListener(new PropertyChangeListener() {

			@Override
			public void propertyChange(PropertyChangeEvent evt) {
				if (evt.getNewValue() instanceof StateValue) {
					StateValue state = (StateValue) evt.getNewValue();
					if (state.equals(StateValue.DONE)) {
						postSA();
					}
				} else if (evt.getPropertyName().equals("progress")) {
					progressBar.setValue((Integer) evt.getNewValue());
				}
			}
		});

		return handler;
	}

	private void postSA() {

		BigDecimal bd = new BigDecimal(
				initialFloorPlan.calculatePowerFloorPlanCost());
		bd = bd.setScale(5, BigDecimal.ROUND_HALF_UP);

		BigDecimal finalBd = new BigDecimal(solution.getSimulatedAnnealingAlg()
				.getSolution().calculatePowerFloorPlanCost());
		finalBd = finalBd.setScale(5, BigDecimal.ROUND_HALF_UP);

		stateLabel.setText("Initial power cost was: "
				+ String.valueOf(bd.doubleValue())
				+ "    Final solution power cost: "
				+ String.valueOf(finalBd.doubleValue()));
		displayPanel.removeAll();

		lblStatus.setText("                              " +
				"Initial power cost was: "
				+ String.valueOf(bd.doubleValue())
				+ "    Final solution power cost: "
				+ String.valueOf(finalBd.doubleValue()));
		
		drawBlocks(solution.getSimulatedAnnealingAlg().getSolution());

		SwingUtilities.getWindowAncestor(progressBar).dispose();
	}

	/**
	 * @param args
	 *            the command line arguments
	 */
	public static void main(String args[]) {
		try {
			// Set cross-platform Java L&F (also called "Metal")
			UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
		} catch (Exception exc) {
		}

		java.awt.EventQueue.invokeLater(new Runnable() {

			public void run() {
				try {
					PowerAwareFP frame = new PowerAwareFP();
					frame.setVisible(true);
					frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
				} catch (IOException ex) {
					Exceptions.printStackTrace(ex);
				}
			}
		});
	}

	private javax.swing.JToolBar stateBar;
	private javax.swing.JToolBar contentBar;
	private javax.swing.JMenuBar menuBar;
	private javax.swing.JProgressBar progressBar;
	private javax.swing.JButton btnParseFile;
	private javax.swing.JButton btnExecute;
	private javax.swing.JButton btnCostGraph;
	private javax.swing.JLabel stateLabel;
	private javax.swing.JMenuItem menuInsertInputFile;
	private javax.swing.JMenu menuFile;
	private javax.swing.JMenu menuEdit;
	private javax.swing.JMenuItem menuConfig;
	private javax.swing.JMenuItem menuExit;
	private javax.swing.JPanel displayPanel;
	private javax.swing.JScrollPane mainPageDisplay;
	private GridBagConstraints gbc_contentBar;
	private GridBagConstraints gbc_stateBar;
	private JMenuItem mntmMinimize;
	private JLabel lblStatus;
	private JButton btnShowInitialFP;

}
